/*
 *  Copyright (c) 2013 Hai Bison
 *
 *  See the file LICENSE at the root directory of this project for copying
 *  permission.
 */

package com.haibison.android.hutieu.utils;

import java.io.File;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
import android.webkit.MimeTypeMap;

import com.haibison.android.hutieu.BuildConfig;
import com.haibison.android.hutieu.ShareProviderUtils;

/**
 * Manager for a map of extensions to MIME types.
 * <p/>
 * <h1>Usage</h1>
 * <p/>
 * This is just a wrapper for {@link MimeTypeMap}. Because {@link MimeTypeMap}
 * does not allow you to change its data. So to make use of this map, you build
 * its data first. Then for some methods asking for MIME types in
 * {@link ShareProviderUtils}, you don't need to specify them.
 * <p/>
 * If some MIME types are not available within this map (probably because you
 * didn't provide them), it tries to find those in {@link MimeTypeMap}. If they
 * are still not available, {@link #MIME_TYPE_UNKNOWN} will be used.
 * <h1>Notes</h1>
 * <p/>
 * Make sure to build this map before you work with the provider. Because it
 * works only on RAM. For example this is <i>wrong</i> approach:
 * <p/>
 * <ol>
 * <li>You build this map in class {@code A}.</li>
 * <li>When the device wakes up, you use the provider in class {@code B}.</li>
 * </ol>
 * <p/>
 * Instead, you should build the map within {@code B}. The block
 * <code>static {}</code> could be useful.
 * <p/>
 * There is a question: why don't we use SQLite? At this moment we think it's
 * not worth making things more complicated. If you guys want SQLite, please
 * file new issue at project page. We'll wait for votes :-)
 * 
 * @author Hai Bison
 */
public class MimeTypes {

    private static final String CLASSNAME = MimeTypes.class.getName();

    /**
     * MIME type for unknown types.
     */
    public static final String MIME_TYPE_UNKNOWN = "*/*";

    /**
     * Prefix for MIME type audios.
     */
    public static final String PREFIX_MIME_TYPE_AUDIO = "audio/";

    /**
     * Prefix for MIME type images.
     */
    public static final String PREFIX_MIME_TYPE_IMAGE = "image/";

    /**
     * Prefix for MIME type videos.
     */
    public static final String PREFIX_MIME_TYPE_VIDEO = "video/";

    /**
     * The map.
     */
    private static final Map<String, String> MAP = new HashMap<String, String>();

    /**
     * This is singleton class.
     */
    private MimeTypes() {
    }// MimeTypes()

    /**
     * Maps {@code extension} to {@code mime}.
     * 
     * @param extension
     *            the extension, note that you <i>shouldn't</i> include the
     *            period prefix ('.')
     * @param mime
     *            the MIME type.
     * @return the previous MIME type mapped, or {@code null} if not available,
     *         or {@code null} if {@code extension} is empty or {@code null}.
     */
    public static String put(String extension, String mime) {
        if (TextUtils.isEmpty(extension))
            return null;
        return MAP.put(extension, mime);
    }// put()

    /**
     * Parses a URI to get its extension, then maps the extension to the MIME
     * type given.
     * 
     * @param uri
     *            the URI.
     * @param mime
     *            the MIME type.
     * @return the previous MIME type mapped, or {@code null} if not available,
     *         or if there is no extension to extract from given URI.
     */
    public static String putUri(String uri, String mime) {
        return put(MimeTypeMap.getFileExtensionFromUrl(uri.toLowerCase()), mime);
    }// put()

    /**
     * Parses a URI to get its extension, then maps the extension to the MIME
     * type given.
     * 
     * @param uri
     *            the URI.
     * @param mime
     *            the MIME type.
     * @return the previous MIME type mapped, or {@code null} if not available,
     *         or if there is no extension to extract from given URI.
     */
    public static String put(Uri uri, String mime) {
        return putUri(uri.toString(), mime);
    }// put()

    /**
     * Parses a URL to get its extension, then maps the extension to the MIME
     * type given.
     * 
     * @param url
     *            the URL.
     * @param mime
     *            the MIME type.
     * @return the previous MIME type mapped, or {@code null} if not available,
     *         or if there is no extension to extract from given URL.
     */
    public static String put(URL url, String mime) {
        return putUri(url.toString(), mime);
    }// put()

    /**
     * Parses a file name to get its extension, then maps the extension to the
     * MIME type given.
     * 
     * @param file
     *            the file.
     * @param mime
     *            the MIME type.
     * @return the previous MIME type mapped, or {@code null} if not available,
     *         or if there is no extension to extract from given file.
     */
    public static String put(File file, String mime) {
        return putUri(file.getName(), mime);
    }// put()

    /**
     * Gets MIME type from an extension. If this map does not contain any MIME
     * type for given extension, tries the system map at {@link MimeTypeMap}.
     * 
     * @param extension
     *            the extension.
     * @return the MIME type mapped, or {@link #MIME_TYPE_UNKNOWN} if not
     *         available.
     */
    public static String get(String extension) {
        String mime = MAP.get(extension);
        if (TextUtils.isEmpty(mime))
            mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
                    extension);
        if (BuildConfig.DEBUG)
            Log.d(CLASSNAME, String.format("get() >> %s = %s", extension, mime));
        return TextUtils.isEmpty(mime) ? MIME_TYPE_UNKNOWN : mime;
    }// get()

    /**
     * Parses a URI to get its extension, then gets the extension's MIME type.
     * If this map does not contain any MIME type for the extension, tries the
     * system map at {@link MimeTypeMap}.
     * 
     * @param uri
     *            the URI.
     * @return the MIME type mapped, or {@link #MIME_TYPE_UNKNOWN} if not
     *         available.
     */
    public static String getUri(String uri) {
        return get(MimeTypeMap.getFileExtensionFromUrl(uri.toLowerCase()));
    }// get()

    /**
     * Parses a URI to get its extension, then gets the extension's MIME type.
     * If this map does not contain any MIME type for the extension, tries the
     * system map at {@link MimeTypeMap}.
     * 
     * @param uri
     *            the URI.
     * @return the MIME type mapped, or {@link #MIME_TYPE_UNKNOWN} if not
     *         available.
     */
    public static String get(Uri uri) {
        return getUri(uri.toString());
    }// get()

    /**
     * Parses a URL to get its extension, then gets the extension's MIME type.
     * If this map does not contain any MIME type for the extension, tries the
     * system map at {@link MimeTypeMap}.
     * 
     * @param url
     *            the URL.
     * @return the MIME type mapped, or {@link #MIME_TYPE_UNKNOWN} if not
     *         available.
     */
    public static String get(URL url) {
        return getUri(url.toString());
    }// get()

    /**
     * Parses a file name to get its extension, then gets the extension's MIME
     * type. If this map does not contain any MIME type for the extension, tries
     * the system map at {@link MimeTypeMap}.
     * 
     * @param file
     *            the file.
     * @return the MIME type mapped, or {@link #MIME_TYPE_UNKNOWN} if not
     *         available.
     */
    public static String get(File file) {
        return getUri(file.getName());
    }// get()

}
